package repositories

import (
	"iris-mvc/models"
	"sync"
	_ "errors"
)

type Query func(models.User) bool



// userRepository
//它是一个可测试的接口，即一个内存或连接到sql数据库。
type UserRepository interface {
    Exec(query Query, action Query, limit int, mode int) (ok bool)
    Select(query Query) (user models.User, found bool)
    SelectMany(query Query, limit int) (results []models.User)
    // InsertOrUpdate(user models.User) (updateduser models.User, err error)
    Delete(query Query, limit int) (deleted bool)
}

//我们示例中唯一的repository类型。
func NewUserRepository(source map[int64]models.User) UserRepository {
    return &userMemoryRepository{source: source}
}

// userRepository是一个userRepository
//使用内存数据源
type userMemoryRepository struct {
    source map[int64]models.User
    mu     sync.RWMutex
}

const (
    // ReadOnlyMode将RLock（读取）数据。
    ReadOnlyMode = iota
    // ReadWriteMode将锁定（读/写）数据。
    ReadWriteMode
)

func (r *userMemoryRepository) Exec(query Query, action Query, actionLimit int, mode int) (ok bool) {
    loops := 0
    if mode == ReadOnlyMode {
        r.mu.RLock()
        defer r.mu.RUnlock()
    } else {
        r.mu.Lock()
        defer r.mu.Unlock()
    }
    for _, user := range r.source {
        ok = query(user)
        if ok {
            if action(user) {
                loops++
                if actionLimit >= loops {
                    break // break
                }
            }
        }
    }
    return
}

//Select接收查询函数
//我们想象中的数据源
//当该函数返回true时，它会停止迭代
//它实际上是一个简单但非常聪明的原型函数
//自从我第一次想到它以来，我一直在使用它，
//希望你会发现它也很有用。
func (r *userMemoryRepository) Select(query Query) (user models.User, found bool) {
    found = r.Exec(query, func(m models.User) bool {
        user = m
        return true
    }, 1, ReadOnlyMode)
    //设置一个空的models.User，如果根本找不到的话。
    if !found {
        user = models.User{}
    }
    return
}

// SelectMany与Select相同但返回一个或多个models.User作为切片。
//如果limit <= 0则返回所有内容。
func (r *userMemoryRepository) SelectMany(query Query, limit int) (results []models.User) {
    r.Exec(query, func(m models.User) bool {
        results = append(results, m)
        return true
    }, limit, ReadOnlyMode)
    return
}

// InsertOrUpdate将user添加或更新到map中存储。
// 
// func (r *userMemoryRepository) InsertOrUpdate(user models.User) (models.User, error) {
//     id := user.ID
//     if id == 0 { // Create new action  //创建新记录
//         var lastID int64
//         //找到最大的ID，以便不重复
//         //在制作应用中，您可以使用第三方
//         //库以生成UUID作为字符串。
//         r.mu.RLock()
//         for _, item := range r.source {
//             if item.ID > lastID {
//                 lastID = item.ID
//             }
//         }
//         r.mu.RUnlock()
//         id = lastID + 1
//         user.ID = id
//         // map-specific thing
//         r.mu.Lock()
//         r.source[id] = user
//         r.mu.Unlock()
//         return user, nil
//     }
//     //基于user.ID更新动作，
//     //这里我们将允许更新海报和流派，如果不是空的话。
//     //或者我们可以做替换：
//     // r.source [id] =user
//     //向下面的代码一样;
//     current, exists := r.Select(func(m models.User) bool {
//         return m.ID == id
//     })
//     if !exists { // ID不是真实的，返回错误。
//         return models.User{}, errors.New("failed to update a nonexistent user")
//     }
//     //或注释这些和r.source[id] = m进行纯替换
//     if user.Poster != "" {
//         current.Poster = user.Poster
//     }
//     if user.Genre != "" {
//         current.Genre = user.Genre
//     }
//     //锁定数据
//     r.mu.Lock()
//     r.source[id] = current
//     r.mu.Unlock()
//     return user, nil
// }



func (r *userMemoryRepository) Delete(query Query, limit int) bool {
    return r.Exec(query, func(m models.User) bool {
        delete(r.source, m.ID)
        return true
    }, limit, ReadWriteMode)
}



